pub mod cli;
pub mod work;

mod code;
mod log;
mod node;
mod runner;

pub use cli::App;
pub use node::Param;
pub use runner::{Ctrl, RunningInfo};

/// FstType 支持类型
#[derive(Debug, Clone)]
pub enum Value {
    String(String),
    Float(f64),
    Int(i64),
    ///  Unexpected Token
    Token(Param),
}

impl From<&str> for Value {
    fn from(s: &str) -> Self {
        Self::String(s.to_string())
    }
}

impl From<String> for Value {
    fn from(s: String) -> Self {
        Self::String(s)
    }
}

impl From<f64> for Value {
    fn from(f: f64) -> Self {
        Self::Float(f)
    }
}

impl From<i32> for Value {
    fn from(n: i32) -> Self {
        Self::Int(n as i64)
    }
}

impl From<i64> for Value {
    fn from(n: i64) -> Self {
        Self::Int(n as i64)
    }
}

impl From<usize> for Value {
    fn from(n: usize) -> Self {
        Self::Int(n as i64)
    }
}

impl From<&Value> for Value {
    fn from(fty: &Value) -> Self {
        fty.clone()
    }
}

impl From<&Param> for Value {
    fn from(p: &Param) -> Self {
        Self::Token(p.clone())
    }
}

impl From<Param> for Value {
    fn from(p: Param) -> Self {
        Self::Token(p)
    }
}

impl From<std::path::PathBuf> for Value {
    fn from(p: std::path::PathBuf) -> Self {
        Self::String(format!("{}", p.display()))
    }
}

impl From<&std::path::PathBuf> for Value {
    fn from(p: &std::path::PathBuf) -> Self {
        Self::String(format!("{}", p.display()))
    }
}

impl Value {
    pub fn display(&self) -> String {
        match self {
            Self::String(val) => val.to_string(),
            Self::Float(val) => format!("{}", val),
            Self::Int(val) => format!("{}", val),
            Self::Token(params) => format!("{:?}", params),
        }
    }

    pub fn is_valid(&self) -> bool {
        match self {
            Value::String(_) | Value::Int(_) | Value::Float(_) => true,
            _ => false,
        }
    }

    pub fn parse(s: &str) -> Self {
        if let Ok(n) = s.parse::<i64>() {
            Self::Int(n)
        } else if let Ok(f) = s.parse::<f64>() {
            Self::Float(f)
        } else {
            Self::String(s.to_string())
        }
    }
}
